import fs from 'fs';
import axios from 'axios';
import path from 'path';
import fsPromises from 'fs-promise';
import router from 'koa-router';
import ContentTypeTool from '../lib/ContentTypeTool';
import awaitWrap from '../lib/awaitWrap';
import configTool from '../com/configTool';
import FSTool from '../lib/FSTool/index';
import readFromDB from '../lib/GISServer/Util/readFromDB';
import readFromNet from '../lib/GISServer/Util/readFromNet';
import crypto from 'crypto';
import saveToDB from '../lib/GISServer/Util/saveToDB';
import initDB from '../lib/GISServer/Util/initDB';
import readFromDisk from '../lib/GISServer/Util/readFromDisk';


const ProxyRoutes = new router({prefix: '/proxyServer'});

function getRequestParams(ctx: any) {
    const protocol = ctx.params.protocol === 'http' ? 'http://' : 'https://';
    const ip = ctx.params.ip;
    const port = ctx.params.port;

    // 获取请求的 Url，去除掉协议、域名、端口、Get参数的相对路径
    const relativeUrl = ctx.params.url;
    let originalUrl = `${protocol}${ip}:${port}/${relativeUrl}`;

    const originalParam = ctx.request.query;

    if (Object.keys(originalParam).length !== 0) {
        originalUrl += '?' + Object.keys(originalParam).map(key => {
            return `${key}=${originalParam[key]}`;
        }).join('&');
    }

    return {protocol, ip, port, relativeUrl, originalUrl};
}


ProxyRoutes
    // http://127.0.0.1:3000/proxyServer/no-cache/http/182.92.77.229/8080/geoserver/ais/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=ais%3Agis_detector_pos&maxFeatures=50&outputFormat=application%2Fjson&BBOX=121.50185823440552,31.231749057769775,121.50619268417358,31.236083507537842
    .get('/no-cache/:protocol/:ip/:port/:url(.*)', async (ctx: any) => {
        const {originalUrl} = getRequestParams(ctx);
        if (originalUrl) {
            let [err, res] = await awaitWrap(axios.get(originalUrl, {responseType: 'arraybuffer'}));
            if (err) {
                ctx.status = 422;
                ctx.body = err;
            } else {
                for (const resKey in res.headers) {
                    ctx.set(resKey, res.headers[resKey]);
                }
                ctx.body = res.data;
            }
        }
    })
    // 例如：
    //      原URL：https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json
    //      调用：http://127.0.0.1:3000/proxyServer/auto-cache/https/geo.datav.aliyun.com/443/areas_v3/bound/100000_full.json
    .get('/auto-cache/:protocol/:ip/:port/:url(.*)', async (ctx: any) => {
        const {ip, port, relativeUrl, originalUrl} = getRequestParams(ctx);

        // 缓存文件保存的绝对路径
        let fileSavePath = path.join(configTool.appBasePath, 'temp/fileOut', `${ctx.params.protocol}/${ip}/${port}/${relativeUrl}`);
        let fileDir = path.dirname(fileSavePath);

        if (originalUrl) {
            // 判断是否有缓存文件
            let [err, res] = await FSTool.readFileAsync(fileSavePath);
            // 缓存文件
            if (res) {
                let contentType = ContentTypeTool.getContentType(fileSavePath);
                ctx.set('Content-Type', contentType);
                ctx.body = res;
            }

            // 未缓存过的其他网络资源
            if (!res) {
                [err, res] = await awaitWrap(axios.get(originalUrl, {responseType: 'arraybuffer'}));
                if (err) {
                    ctx.status = 422;
                    ctx.body = err;
                } else {
                    for (const resKey in res.headers) {
                        ctx.set(resKey, res.headers[resKey]);
                    }
                    ctx.body = res.data;
                    // 存入缓存文件
                    if (configTool.preservableONFile()) {
                        // 如果 Url 里面有文件名，则保存到文件中
                        if (!path.extname(fileSavePath)) {
                            fileSavePath += ContentTypeTool.getExt(res.headers['content-type']);
                        }
                        await fsPromises.ensureDir(fileDir);
                        fs.writeFileSync(fileSavePath, res.data);
                    }
                }
            }
        }
    })
    .get('/wall-Proxy/:protocol/:ip/:port/:url(.*)', async (ctx: any) => {

        const {ip, port, relativeUrl, originalUrl} = getRequestParams(ctx);

        // 缓存文件保存的绝对路径
        const fileSavePath = path.join(configTool.appBasePath, 'temp/fileOut', `${ctx.params.protocol}/${ip}/${port}/${relativeUrl}`);

        const dbPath = '\\' + relativeUrl.replaceAll('/', '\\');

        if (originalUrl) {
            let err, buffer, dataSource;
            // 从数据库中获取文件
            await initDB(ip);
            [err, buffer, dataSource] = await readFromDB({DBName: ip, relativePath: dbPath});
            // 判断是否有缓存文件
            [err, buffer, dataSource] = await readFromDisk({fileSavePath, err, buffer, dataSource});

            // 从网络获取
            [err, buffer, dataSource] = await readFromNet({
                url: originalUrl, headers: {}, err, buffer, dataSource, option: {
                    proxy: {
                        protocol: 'http',
                        host: '127.0.0.1',
                        port: 7890
                    }
                }
            });


            if (buffer) {
                let contentType = ContentTypeTool.getContentType(fileSavePath);
                ctx.set('Content-Type', contentType);
                ctx.body = buffer;


                // 存入缓存文件
                const md5Str = crypto.createHash('md5').update(buffer).digest('hex');
                if (md5Str) {
                    saveToDB({DBName: ip, relativePath: dbPath, buffer}).then();
                }
            } else {
                ctx.status = 422;
                ctx.set('Content-Type', 'application/json;charset=utf-8');
                ctx.body = err;
                console.warn('代理 翻墙路径失败');
            }


        }
    });


export default ProxyRoutes;
